package com.zhanghu.backendZray.aspect;

import cn.hutool.core.util.StrUtil;
import com.zhanghu.backendZray.annotation.MenuNeed;
import com.zhanghu.backendZray.cache.ContextCache;
import com.zhanghu.backendZray.cache.UserMenuCache;
import com.zhanghu.backendZray.exception.ApiException;
import com.zhanghu.backendZray.pojo.dto.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.List;

/**
 * @author ZhangDong
 * @date 2024/9/11 9:31
 */
@Component
@Aspect
@Slf4j
public class MenuAspect {

    @Pointcut("execution(* com.zhanghu.backendZray.controller..*.*(..))")
    public void allController() {}

    @Around("allController()")
    public Object allController(ProceedingJoinPoint point) throws Throwable {
        Object target = point.getTarget();
        Class<?> aClass = target.getClass();
        MenuNeed annotation = aClass.getAnnotation(MenuNeed.class);
        if (annotation == null) {
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            annotation = method.getAnnotation(MenuNeed.class);
        }
        if (annotation == null) {
            return point.proceed();
        }
        // 这样做因为threadLocal里的数据用完后没清理，会出现共用同一个线程池里的线程，那么这里不为空
        // 所以我改为了拦截器里，遇到token为空的情况，也要设置：ContextCache.setCurrentUser(null);
        // 因为执行顺序是 拦截器-> 切面 -> 具体执行的方法
        Integer currentUserId = ContextCache.currentUserId();
        if (currentUserId == null) {
            throw new ApiException(ApiResponse.Status.UNAUTHORIZED, "未登录，或者登录状态已过期");
        }
        // 获取此用户的菜单权限
        String menuName = annotation.menuName();
        if (StrUtil.isEmpty(menuName)) {
            return point.proceed();
        }
        List<String> menuList = UserMenuCache.getMenuList(currentUserId);
        if (!menuList.contains(menuName)) {
            throw new ApiException(ApiResponse.Status.FORBIDDEN, "您没有此操作权限！");
        }
        return point.proceed();
    }
}
